home *** CD-ROM | disk | FTP | other *** search
- //
- // File: QTSndTween.c
- //
- // Contains: Sound tweening support for QuickTime movies.
- //
- // Written by: Tim Monroe
- // based largely on the tween sample code in the QuickTime 2.5 Developers Guide
- // and the sample code QT3DTween.c.
- //
- // Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <2> 05/26/98 rtm set the time scale of the sound track media to that of the movie,
- // using revised code from Peter Hoddie
- // <1> 04/10/98 rtm first file; revised to personal coding style
- //
- //
- // This sample shows how to modify an existing QuickTime movie so that the volume of its sound track
- // is gradually increased (or decreased) as the movie plays. We do this by adding a tween track to
- // the movie and linking the tween track to the existing sound track.
- //
- // NOTES:
- //
- // ••• (1) •••
- // For complete information on creating tween media tracks, see the chapter "Tween Media Handler Components"
- // in the QuickTime 2.5 or 3.0 Developers Guide.
- //
- //
-
- #include <FixMath.h>
- #include <Sound.h>
-
- #include "QTSndTween.h"
-
- // global variables
- // this variable determines what kind of tween data we add to the movie
-
- Boolean gTweenLoToHigh = true; // do we start at no volume and end at full volume?
-
-
- //////////
- //
- // QTSndTween_OpenMovie
- // Have the user select a QuickTime movie.
- //
- //////////
-
- Movie QTSndTween_OpenMovie (void)
- {
- SFTypeList myTypeList;
- StandardFileReply myReply;
- Movie myMovie = NULL;
- short myResRefNum = 0;
- OSErr myErr = noErr;
-
- // prompt the user for a movie
- myTypeList[0] = MovieFileType;
-
- StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- // open a movie file using the FSSpec and create a movie from that file
- myErr = OpenMovieFile(&myReply.sfFile, &myResRefNum, 0);
- if (myErr != noErr)
- goto bail;
-
- myErr = NewMovieFromFile(&myMovie, myResRefNum, NULL, NULL, newMovieActive, NULL);
- if (myErr != noErr)
- goto bail;
-
- bail:
- // we're done with the movie file, so close it
- if (myResRefNum != 0)
- CloseMovieFile(myResRefNum);
-
- return(myMovie);
- }
-
-
- //////////
- //
- // QTSndTween_AddTweenTrackToMovie
- // Add a tween track to a QuickTIme movie.
- //
- //////////
-
- OSErr QTSndTween_AddTweenTrackToMovie (void)
- {
- Movie myMovie = NULL;
- Track mySndTrack = NULL;
- Track myTrack;
- Media myMedia;
- StandardFileReply myReply;
- SampleDescriptionHandle mySampleDesc = NULL;
- QTAtomContainer mySample = NULL;
- QTAtomContainer myInputMap = NULL;
- QTAtom myAtom = 0;
- QTAtom myInputAtom = 0;
- short myTweenData[2];
- long myRefIndex;
- TimeRecord myTimeRec;
- OSErr myErr = noErr;
-
- //////////
- //
- // have the user select a movie
- //
- //////////
-
- myMovie = QTSndTween_OpenMovie();
- if (myMovie == NULL)
- goto bail;
-
- //////////
- //
- // get the (first) sound track from the movie
- //
- //////////
-
- mySndTrack = GetMovieIndTrackType(myMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
- if (mySndTrack == NULL)
- goto bail;
-
- //////////
- //
- // create the tween track and media, and a sample to contain the tween data
- //
- //////////
-
- // create the tween track and media
- myTrack = NewMovieTrack(myMovie, 0, 0, kNoVolume);
- myMedia = NewTrackMedia(myTrack, TweenMediaType, kTweenTimeScale, NULL, 0);
-
- // create a new sample; this sample will hold the tween data
- myErr = QTNewAtomContainer(&mySample);
- if (myErr != noErr)
- goto bail;
-
- myTweenData[0] = gTweenLoToHigh ? EndianU16_NtoB(0) : EndianU16_NtoB(512);
- myTweenData[1] = gTweenLoToHigh ? EndianU16_NtoB(512) : EndianU16_NtoB(0);
-
- // make a tween entry for that data;
- // a tween entry is a parent atom that contains leaf atoms describing the tweening operation
- myErr = QTSndTween_AddTweenEntryToSample(mySample, kSoundTweenID, kTweenTypeShort, &myTweenData, sizeof(myTweenData));
- if (myErr != noErr)
- goto bail;
-
- // create the sample description
- mySampleDesc = (SampleDescriptionHandle)NewHandleClear(sizeof(SampleDescription));
- if (mySampleDesc == NULL)
- goto bail;
-
- (**mySampleDesc).descSize = sizeof(SampleDescription);
-
- // add the tween sample to the media
- BeginMediaEdits(myMedia);
-
- // set the time scale of the media to that of the movie
- myTimeRec.value.lo = GetTrackDuration(mySndTrack);
- myTimeRec.value.hi = 0;
- myTimeRec.scale = GetMovieTimeScale(myMovie);
- ConvertTimeScale(&myTimeRec, GetMediaTimeScale(myMedia));
-
- myErr = AddMediaSample(myMedia, mySample, 0, GetHandleSize(mySample), myTimeRec.value.lo, (SampleDescriptionHandle)mySampleDesc, 1, 0, NULL);
- if (myErr != noErr)
- goto bail;
-
- EndMediaEdits(myMedia);
-
- // add the media to the track
- InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
-
- // dispose of some things we no longer need
- QTDisposeAtomContainer(mySample);
- DisposeHandle((Handle)mySampleDesc);
-
- //////////
- //
- // create a link between the sound track and the tween track, and update the sound track's input map
- //
- //////////
-
- // first, create a new atom container
- myErr = QTNewAtomContainer(&myInputMap);
- if (myErr != noErr)
- goto bail;
-
- // for *each* tween entry in the tween media sample,
- // create a link between the sound track and the tween track, and add an entry to the input map
-
- myErr = AddTrackReference(mySndTrack, myTrack, kTrackModifierReference, &myRefIndex);
- if (myErr != noErr)
- goto bail;
-
- myErr = QTSndTween_AddTweenEntryToInputMap(myInputMap, myRefIndex, kSoundTweenID, kTrackModifierTypeVolume, NULL);
- if (myErr != noErr)
- goto bail;
-
- // attach the input map to the sound media
- myErr = SetMediaInputMap(GetTrackMedia(mySndTrack), myInputMap);
- if (myErr != noErr)
- goto bail;
-
- // dispose of the input map
- QTDisposeAtomContainer(myInputMap);
-
- //////////
- //
- // finish up
- //
- //////////
-
- // save the new movie file
- StandardPutFile("\pSave Movie as:", "\pNewMovie.mov", &myReply);
- if (myReply.sfGood) {
- FlattenMovieData(myMovie, flattenAddMovieToDataFork, &myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile);
- myErr = GetMoviesError();
- }
-
- bail:
- return(myErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Tween utilities.
- //
- // Use these functions add tween entries to samples or to add attributes to tween entries.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QTSndTween_AddTweenEntryToSample
- // Add a tween entry to the specified sample.
- //
- // A tween entry defines a set of values for a single tweening operation. A tween entry is a parent atom
- // whose children define the tween data type, the tween data, and additional attributes of the operation.
- //
- // The data specified in the theData parameter is assumed to be in big-endian format.
- //
- //////////
-
- OSErr QTSndTween_AddTweenEntryToSample (QTAtomContainer theSample, QTAtomID theID, QTAtomType theType, void *theData, long theDataSize)
- {
- OSErr myErr = noErr;
- QTAtom myAtom;
-
- // create an entry for this tween in the sample
- myErr = QTInsertChild(theSample, kParentAtomIsContainer, kTweenEntry, theID, 0, 0, NULL, &myAtom);
- if (myErr != noErr)
- goto bail;
-
- // set the type of this tween entry
- theType = EndianU32_NtoB(theType);
- myErr = QTInsertChild(theSample, myAtom, kTweenType, 1, 0, sizeof(theType), &theType, NULL);
- if (myErr != noErr)
- goto bail;
-
- // set the data for this tween entry
- myErr = QTInsertChild(theSample, myAtom, kTweenData, 1, 0, theDataSize, theData, NULL);
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // QTSndTween_AddTweenEntryToInputMap
- // Add a tween entry to the specified input map.
- //
- //////////
-
- OSErr QTSndTween_AddTweenEntryToInputMap (QTAtomContainer theInputMap, long theRefIndex, long theID, OSType theType, char *theName)
- {
- QTAtom myInputAtom;
- OSErr myErr = noErr;
-
- // add an entry to the input map
- myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, theRefIndex, 0, 0, NULL, &myInputAtom);
- if (myErr != noErr)
- goto bail;
-
- // add two child atoms to the parent atom;
- // these atoms define the type of the modifier input and the ID of the tween entry atom
- theType = EndianU32_NtoB(theType);
- myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(OSType), &theType, NULL);
- if (myErr != noErr)
- goto bail;
-
- theID = EndianU32_NtoB(theID);
- myErr = QTInsertChild(theInputMap, myInputAtom, kInputMapSubInputID, 1, 0, sizeof(long), &theID, NULL);
- if (myErr != noErr)
- goto bail;
-
- // set the name of the input atom
- if (theName != NULL) {
- long myLength = 1;
- Ptr myPtr = theName;
- UInt16 *myShort;
-
- // determine the length of the name string
- while (*myPtr++)
- myLength++;
-
- // convert the name string to the proper endian format
- myPtr = theName;
- while (*myPtr) {
- myShort = (UInt16 *)myPtr;
- *myPtr = EndianU16_NtoB(*myShort);
- myPtr = myPtr + 2; // point to next word
- }
-
- myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierInputName, 1, 0, myLength, theName, NULL);
- }
-
- bail:
- return(myErr);
- }